﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Web.Services.Protocols;
using Microsoft.Crm.Sdk;
using Microsoft.Crm.Sdk.Metadata;
using Microsoft.Crm.SdkTypeProxy;
using Microsoft.Crm.SdkTypeProxy.Metadata;

namespace OrbitOne.CRM.Plugins.PhonenumberCleanupInstaller
{
    class PhonenumberCleanupInstaller
    {
        private static CrmService m_service;
        private static MetadataService m_metadataService;
        private static CrmServiceWrapper m_serviceWrapper;

        private static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Creating services");
                m_serviceWrapper = new CrmServiceWrapper();
                m_metadataService = m_serviceWrapper.MetaDataService;
                m_service = m_serviceWrapper.Service;

                Console.WriteLine("Creating new entities (countries and areacodes");
                createNewEntities();

                Console.WriteLine("Adding the records to the newly created entities");
                populateNewEntities();

                Console.WriteLine("Start plugin registration");
                registerPlugin();
            }
            catch (SoapException ex)
            {
                Console.WriteLine(ex.Detail.InnerXml);
                Console.WriteLine(ex);
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
        }

        private static void registerPlugin()
        {
            var config = CrmConfiguration.Load();
            m_pluginregistrationxml = string.Format(m_pluginregistrationxml, config.Url, config.Instance, config.Domain, config.Username);
            m_connections = string.Format(m_connections, config.Url, config.Domain, config.Username);

            var sw = new StreamWriter("MatchNameConnection.config");
            sw.Write(m_connections);
            sw.Flush();
            sw.Close();
            sw = new StreamWriter("MatchNameReg.xml");
            sw.Write(m_pluginregistrationxml);
            sw.Flush();
            sw.Close();
            var process = new ProcessStartInfo("PluginRegistration.exe",
                                               "/c:MatchNameConnection.config /f:MatchNameReg.xml /cl:PluginDeployment /op:import /n:false /org:"
                                                 + config.Instance);

            Process.Start(process);
        }

        private static void createNewEntities()
        {
            createCountryEntity();
            createAreaCodeEntity();
            m_service.Execute(new PublishAllXmlRequest());
        }
        private static void populateNewEntities()
        {
            var countries = Country.Load();
            countries.ForEach(country => country.UploadEntity(m_service));

            var mapper = countries.ToDictionary(c => c.Id, c => c.newId);

            var areas = AreaCode.Load();
            areas.ForEach(area => area.CountryId = mapper[area.CountryId]);
            areas.ForEach(area => area.UploadEntity(m_service));
        }

        private static void createAreaCodeEntity()
        {
            var primaryAttribute = getStringAttribute("new_name",
                                                      "Name",
                                                      "Stores the areacode name",
                                                      100,
                                                      AttributeRequiredLevel.Required);

            var relation = new OneToManyMetadata
                               {
                                   ReferencedEntity = "new_country",
                                   ReferencingEntity = "new_areacode",
                                   SchemaName = "new_countryid",
                                   AssociatedMenuBehavior = new CrmAssociatedMenuBehavior
                                                                {
                                                                    Value = AssociatedMenuBehavior.UseLabel
                                                                },
                                   AssociatedMenuGroup = new CrmAssociatedMenuGroup(AssociatedMenuGroup.Details),
                                   AssociatedMenuLabel =
                                       Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("AreaCode", 1033),
                                   AssociatedMenuOrder = new CrmNumber(10000),
                                   CascadeAssign = new CrmCascadeType(CascadeType.Cascade),
                                   CascadeDelete = new CrmCascadeType(CascadeType.Cascade),
                                   CascadeReparent = new CrmCascadeType(CascadeType.Cascade),
                                   CascadeShare = new CrmCascadeType(CascadeType.Cascade),
                                   CascadeUnshare = new CrmCascadeType(CascadeType.Cascade)
                               };

            var entity = new EntityMetadata
            {
                OwnershipType = new CrmOwnershipTypes(OwnershipTypes.OrgOwned),
                Description = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Stores the area codes which help in the phone cleanup plugin by OritOne", 1033),
                DisplayName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("AreaCode", 1033),
                DisplayCollectionName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("AreaCodes", 1033),
                SchemaName = "new_areacode"
            };
            m_metadataService.Execute(new CreateEntityRequest
                                          {
                                              PrimaryAttribute = primaryAttribute,
                                              Entity = entity,
                                              HasActivities = false,
                                              HasNotes = false
                                          });
            m_metadataService.Execute(new CreateAttributeRequest
                                          {
                                              EntityName = "new_areacode",
                                              Attribute = getStringAttribute("new_areacode",
                                                                             "Area Code",
                                                                             "The area code in the country",
                                                                             7,
                                                                             AttributeRequiredLevel.Recommended)
                                          });
            m_metadataService.Execute(new CreateOneToManyRequest
                                          {
                                              Lookup = new LookupAttributeMetadata
                                                           {
                                                               SchemaName = "new_countryid",
                                                               AttributeType = new CrmAttributeType { Value = AttributeType.Lookup },
                                                               DisplayName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Country", 1033),
                                                               RequiredLevel = new CrmAttributeRequiredLevel(AttributeRequiredLevel.Recommended),
                                                               Description = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Country", 1033)
                                                           },
                                              OneToManyRelationship = relation
                                          });
        }
        private static void createCountryEntity()
        {
            var primaryAttribute = getStringAttribute("new_name",
                                                      "English Name",
                                                      "Stores the english short name of the country",
                                                      100,
                                                      AttributeRequiredLevel.Required);
            var entity = new EntityMetadata
            {
                OwnershipType = new CrmOwnershipTypes(OwnershipTypes.OrgOwned),
                Description = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Stores the Countries which help in the phone cleanup plugin by OritOne", 1033),
                DisplayName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Country", 1033),
                DisplayCollectionName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel("Countries", 1033),
                SchemaName = "new_country"
            };

            m_metadataService.Execute(new CreateEntityRequest
                                          {
                                              PrimaryAttribute = primaryAttribute,
                                              Entity = entity,
                                              HasActivities = false,
                                              HasNotes = false
                                          });
            m_metadataService.Execute(new CreateAttributeRequest
                                          {
                                              EntityName = "new_country",
                                              Attribute = getStringAttribute("new_telephoneprefix",
                                                                             "Telephone prefix",
                                                                             "The telephone prefix of the country",
                                                                             5,
                                                                             AttributeRequiredLevel.Recommended)
                                          });
        }
        private static StringAttributeMetadata getStringAttribute(string name, string displayname, string description, int length, AttributeRequiredLevel requiredLevel)
        {
            return new StringAttributeMetadata
            {
                SchemaName = name,
                DisplayName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel(displayname, 1033),
                RequiredLevel = new CrmAttributeRequiredLevel { Value = requiredLevel },
                Description = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel(description, 1033),
                AttributeType = new CrmAttributeType(AttributeType.String),
                MaxLength = new CrmNumber(length)
            };
        }
        private static IntegerAttributeMetadata getIntAttribute(string name, string displayname, string description, int minvalue, int maxvalue, AttributeRequiredLevel requiredLevel)
        {
            return new IntegerAttributeMetadata
            {
                SchemaName = name,
                DisplayName = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel(displayname, 1033),
                RequiredLevel = new CrmAttributeRequiredLevel { Value = requiredLevel },
                Description = Microsoft.Crm.Sdk.Utility.CrmServiceUtility.CreateSingleLabel(description, 1033),
                MinValue = new CrmNumber(minvalue),
                MaxValue = new CrmNumber(maxvalue)
            };
        }
        private static string m_connections =
               @"<?xml version=""1.0""?>
                    <ArrayOfCrmConnection xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
                      <CrmConnection>
                        <Label>PluginDeployment</Label>
                        <DiscoveryServerName>{0}</DiscoveryServerName>
                        <DiscoveryServerPort xsi:nil=""true"" />
                        <UserDomain>{1}</UserDomain>
                        <UserName>{2}</UserName>
                      </CrmConnection>
                    </ArrayOfCrmConnection>";
        private static string m_pluginregistrationxml =
            @"<Register LogFile=""Plug-in Registration Log.txt"" Server=""{0}"" Org=""{1}"" Domain=""{2}"" UserName=""{3}"">
                <Solution SourceType=""0"" Assembly=""OrbitOne.CRM.Plugins.PhonenumberCleanup.dll"" Id=""1dbbba20-d9df-46bd-9d12-12daf4c647ac"">
                  <PluginTypes>
                    <Plugin TypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" FriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" Id=""53ed9f9d-6e55-46ad-90f1-965b3cbf27e4"">
                      <Steps>
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Create of contact in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Create"" Mode=""0"" PrimaryEntityName=""contact"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""6c05ec4a-9fa6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step>
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Create of account in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Create"" Mode=""0"" PrimaryEntityName=""account"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""6b05ec4a-9fa6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step>
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Update of account in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Update"" Mode=""0"" PrimaryEntityName=""account"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""17b1f95a-a1a6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step> 
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Update of contact in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Update"" Mode=""0"" PrimaryEntityName=""contact"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""03b069bf-a8a6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step>
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Update of lead in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Update"" Mode=""0"" PrimaryEntityName=""lead"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""7b5fabc9-a8a6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step>
                        <Step PluginTypeName=""Orbitone.CRM.Plugins.PhonenumberCleanup.PhonenumberCleanup"" PluginTypeFriendlyName=""fd8539c7-60a1-426e-8b5c-b9bff3c07432"" CustomConfiguration="""" SecureConfiguration="""" Description=""Create of lead in Parent Pipeline"" FilteringAttributes="""" ImpersonatingUserId="""" InvocationSource=""0"" MessageName=""Create"" Mode=""0"" PrimaryEntityName=""lead"" SecondaryEntityName=""none"" Stage=""10"" SupportedDeployment=""0"" Rank=""1"" Id=""793291da-a8a6-de11-9093-005056bd3ea9"">
                          <Images /> 
                        </Step>
                      </Steps>
                    </Plugin>
                  </PluginTypes>
                </Solution>
              </Register>";
    }
}
